<?php

namespace s94\wechat;

use Exception;

/**
 * 微信服务商支付
 */
class PayPartner extends Pay
{
    /**通用支付接口
     * @param string $type 支付类型：app，h5，native，jsapi
     * @param string $out_trade_no 商户单号
     * @param int $money 支付金额，单位：分
     * @param string $description 商品描述
     * @param array $extend 扩展数据，格式参考文档
     * @return array
     * @throws Exception
     */
    public function pay($type, $out_trade_no, $money, $description, $extend=[])
    {
        self::assert(in_array($type, ['app','h5','native','jsapi']),"支付类型错误");
        $post_data = [
            'sp_appid' => $this->config('appid'),
            'sub_appid' => $this->config('sub_appid',''),
            'sp_mchid' => $this->config('mchid'),
            'sub_mchid' => $this->config('sub_mchid'),
            'description' => $description,
            'out_trade_no' => $out_trade_no,
            'notify_url' => $this->config('notify_url'),
            'amount' => [
                'total' => (int)$money,
                'currency' => 'CNY'
            ],
        ];
        switch ($type){
            case 'jsapi':{
                self::assert(!empty($extend['payer']) && (!empty($extend['payer']['sp_openid'])||!empty($extend['payer']['sub_openid'])),"缺少openid");
            }break;
            case 'h5':{
                self::assert(!empty($extend['scene_info']) && !empty($extend['scene_info']['payer_client_ip']),"缺少payer_client_ip");
                if (!isset($extend['scene_info']['h5_info'])) $extend['scene_info']['h5_info'] = [];
                if (!isset($extend['scene_info']['h5_info']['type'])) $extend['scene_info']['h5_info']['type'] = 'Wap';
            }break;
        }
        if ($extend) $post_data = array_merge_recursive($post_data, $extend);
        $res = $this->apiPay('v3/pay/partner/transactions/'.$type, $post_data);
        return $res;
    }

    /**jsapi支付
     * @param string $out_trade_no 商户单号
     * @param int $money 支付金额，单位：分
     * @param string $description 商品描述
     * @param string $openid 支付者openid，可以添加“sub:”前缀来表示子商户对应的openid，返回，例如：sub:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
     * @param array $extend 扩展数据，格式参考微信官方文档
     * @return array 带有paySign的配置参数，当openid为子商户的时，返回的配置参数的appid也为子商户对应的appid
     * @throws Exception
     */
    public function jsapi($out_trade_no, $money, $description, $openid, $extend=[])
    {
        $js_appid = null;
        if (preg_match("/^sub:/",$openid)){
            self::assert($this->config('sub_appid',''), '使用子商户应用对应的openid时，配置【sub_appid】不能为空');
            $payer = ['payer'=> ['sub_openid'=>substr($openid, 4)]];
            $js_appid = $this->config('sub_appid','');
        }else{
            $payer = ['payer'=> ['sp_openid'=>$openid]];
        }
        $extend = $extend ? array_merge_recursive($extend, $payer) : $payer;
        $res = $this->pay('jsapi', $out_trade_no, $money, $description, $extend);
        return $this->jsapiConfig($res['prepay_id'], $js_appid);
    }

    /**查询支付单详情
     * @param string $out_trade_no 商户单号
     * @param string $transaction_id 微信支付订单号，和$out_trade_no二选一
     * @return mixed
     * @throws Exception
     */
    public function info($out_trade_no, $transaction_id=null)
    {
        self::assert($out_trade_no || $transaction_id, '缺少参数');
        $query = [
            'sp_mchid'=> $this->config('mchid'),
            'sub_mchid'=> $this->config('sub_mchid')
        ];
        if ($out_trade_no){
            $api = 'v3/pay/partner/transactions/out-trade-no/'.$out_trade_no;
        }elseif ($transaction_id){
            $api = 'v3/pay/partner/transactions/id/'.$transaction_id;
        }
        $api .= '?'.http_build_query($query);
        $res = $this->apiPay($api);
        return $res;
    }

    /**关闭订单
     * @param string $out_trade_no 商户单号
     * @return null
     */
    public function close($out_trade_no)
    {
        $post_data = [
            'sp_mchid'=> $this->config('mchid'),
            'sub_mchid'=> $this->config('sub_mchid')
        ];
        $res = $this->apiPay('v3/pay/partner/transactions/out-trade-no/'.$out_trade_no.'/close', $post_data);
        return $res;
    }
    
    /**退款
     * @param string $out_trade_no 退款的支付单的商户单号
     * @param string $out_refund_no 退款单号
     * @param int $money 退款金额，单位：分
     * @param int $total 订单总金额，单位：分
     * @param string $reason 退款原因
     * @param array $extend 扩展数据，格式参考微信官方文档
     * @return array 退款返回数据，具体参考微信官方文档
     */
    public function refund($out_trade_no, $out_refund_no, $money, $total, $reason='', $extend=[])
    {
        $extend['sub_mchid'] = $this->config('sub_mchid');
        return parent::refund($out_trade_no, $out_refund_no, $money, $total, $reason, $extend);
    }

    /**退款详情
     * @param string $out_refund_no 退款单号
     * @return mixed
     */
    public function refundInfo($out_refund_no)
    {
        $api = 'v3/refund/domestic/refunds/'.$out_refund_no.'?'.http_build_query(['sub_mchid'=>$this->config('sub_mchid')]);
        $res = $this->apiPay($api);
        return $res;
    }

}
